package com.hhf.rpa.menu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hhf.rpa.menu.mapper.MenuMapper;
import com.hhf.rpa.menu.model.Menu;
import com.hhf.rpa.menu.pojo.dto.MenuTree;
import com.hhf.rpa.menu.pojo.form.MenuForm;
import com.hhf.rpa.menu.service.MenuService;
import com.hhf.rpa.util.CoreAssert;
import com.hhf.rpa.util.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    public IPage<List<Menu>> getMenuPage(MenuForm form) {
        IPage page = new Page(form.getCurrent(),form.getSize());
        String menuCode = form.getMenuCode();
        String menuName = form.getMenuName();
        Integer parentMenuId = form.getParentMenuId();
        String menuUri = form.getMenuUri();
        Integer menuType = form.getMenuType();
        Integer state = form.getState();
        String menuAlias = form.getMenuAlias();
        String subCode = form.getSubCode();

        LambdaQueryWrapper<Menu> lqw = new LambdaQueryWrapper();
        lqw.like(StringUtils.isNotBlank(menuCode), Menu::getMenuCode, menuCode);
        lqw.like(StringUtils.isNotBlank(menuName), Menu::getMenuName, menuName);
        lqw.like(StringUtils.isNotBlank(menuUri), Menu::getMenuUri, menuUri);
        lqw.like(StringUtils.isNotBlank(menuAlias), Menu::getMenuAlias, menuAlias);
        lqw.likeLeft(StringUtils.isNotBlank(subCode), Menu::getSubCode, subCode);
        lqw.eq(parentMenuId != null, Menu::getParentMenuId, parentMenuId);
        lqw.eq(menuType != null, Menu::getMenuType, menuType);
        lqw.eq(state != null, Menu::getState, state);
        lqw.orderByAsc(Menu::getSort);
        return baseMapper.selectPage(page,lqw);
    }

    /**
     * 按层级嵌套组装
     * @return
     */
    @Override
    public List<MenuTree> getMenuTree() {
        LambdaQueryWrapper<Menu> lqw = new LambdaQueryWrapper();
        lqw.eq(Menu::getMenuType, 1);
        lqw.eq(Menu::getState, 1);
        lqw.orderByAsc(Menu::getSort);
        List<Menu> list = list(lqw);
        if(!CollectionUtils.isEmpty(list)) {
            return buildTree(list, 0);
        }
        return null;
    }

    @Override
    public Menu getByMenuCode(String menuCode) {
        LambdaQueryWrapper<Menu> lqw = new LambdaQueryWrapper();
        lqw.eq(Menu::getMenuCode, menuCode);
        List<Menu> list = list(lqw);
        if (list != null && list.size()>0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public void saveMenu(Menu entity) {
        Date created = new Date();
        entity.setCreated(created);
        entity.setUpdated(created);
        if(entity.getSort() == null) {
             entity.setSort(0);
        }
        if(entity.getParentMenuId() == null) {
            entity.setParentMenuId(0);
        }
        // 更新subCode和menuLevel，按父级ID计算subCode和menuLevel，subcode三个数字作为一个层级，从100开始到999，每个层级允许有899个子项
        Integer parentMenuId = entity.getParentMenuId();
        String parentSubCode = null;
        Menu parentMenu = null;
        if(parentMenuId != null) {
            parentMenu = getById(parentMenuId);
            if(parentMenu != null) {
                parentSubCode = parentMenu.getSubCode();
            }
        }
        String latestBrotherSubCode = getLatestBrotherSubCode(parentMenuId, parentSubCode);
        entity = buildOtherArgs(entity, parentMenu, latestBrotherSubCode);
        saveOrUpdate(entity);
    }

    /**
     * 找出兄弟节点最大subCode
     * @param parentMenuId
     * @param parentSubCode
     * @return
     */
    private String getLatestBrotherSubCode(Integer parentMenuId, String parentSubCode) {
        if(parentMenuId == null){
            parentMenuId = 0;
        }
        QueryWrapper<Menu> qw = new QueryWrapper();
        qw.eq("parent_menu_id", parentMenuId);
        qw.likeRight(StringUtils.isNotBlank(parentSubCode),"sub_code", parentSubCode);
        qw.eq("state", 1);
        qw.select("max(sub_code) as maxSubCode");
        List<Map<String, Object>> list = this.baseMapper.selectMaps(qw);
        if(list != null && list.size()>0) {
            if (list.get(0) != null) {
                return list.get(0).get("maxSubCode").toString();
            }
        }
        return null;
    }

    /**
     * 给 subCode, level等字段重新赋值
     * subCode规则：第一级从100开始，往后每增加一级拼接一个从100开始的数字，以此类推，一个层级做多可有100-999=899个子节点
     * subCode赋值逻辑：先查询兄弟节点，如果没有兄弟节点，subCode = 父节点subCode加100(如果parentId是0，直接赋值100)，
     * 如果有兄弟节点，则取兄弟节点最大subCode加1
     * @param entity
     * @return
     */
    private Menu buildOtherArgs(Menu entity, Menu parentMenu, String latestBrotherSubCode) {
        String subCode = null;
        String parentSubCode = "";

        // 查询父节点信息
        if(parentMenu!= null && parentMenu.getMenuId() != null) {
            parentSubCode = parentMenu.getSubCode();
        }
        // 如果没有兄弟节点
        if(latestBrotherSubCode == null) {
            subCode = parentSubCode+"100";
        } else {
            // 如果有兄弟节点，取后三位+1，然后再和后三位前面的字符串拼接起来
            String last3Code = latestBrotherSubCode.substring(latestBrotherSubCode.length() - 3);
            String latestBrotherSubCodeWithoutLast3Code = latestBrotherSubCode.substring(0,latestBrotherSubCode.length() - 3);
            subCode =  latestBrotherSubCodeWithoutLast3Code + String.valueOf(Integer.parseInt(last3Code)+1);
        }
        // 层级 = 编码长度除以3
        int level = subCode.length() / 3;
        entity.setSubCode(subCode);
        entity.setMenuLevel(level);
        return entity;
    }

    /**
     * 将指定的list递归转换成为树结构的数据
     * @param list     集合对象，每个对象都有用来表示上下级关系的属性结构
     * @param topMenuId 最顶级的id
     * @return MenuTree
     */
    private List<MenuTree> buildTree(List<Menu> list, int topMenuId){
        List<MenuTree> menuTrees = new ArrayList<>();
        for (Menu menu : list) {
            MenuTree menuTree = new MenuTree();
            BeanUtils.copyProperties(menu,menuTree);
            Integer menuId = menu.getMenuId();
            Integer parentMenuId = menu.getParentMenuId();
            CoreAssert.notNull(parentMenuId, "parentMenuId为空");
            if (topMenuId == parentMenuId.intValue()) {
                List<MenuTree> childMenuTrees = buildTree(list, menuId);
                menuTree.setChilds(childMenuTrees);
                menuTrees.add(menuTree);
            }
        }
        return menuTrees;
    }
}
